package indzcraft.calc;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map.Entry;

import org.json.JSONException;
import org.json.JSONObject;

import indzcraft.loader.BaseStats;
import indzcraft.loader.Enchant;
import indzcraft.loader.GearBuffDB;
import indzcraft.loader.Gem;
import indzcraft.loader.IndzCraftLoader;
import indzcraft.loader.ItemEquiped;
import indzcraft.loader.Reforge;
import indzcraft.loader.SocketBonus;

public class IndzCraftCalc {
	
	public static void main(String[] args){
		new IndzCraftCalc();
	}

	Calc calculator;
	double ap;
	Stats stats;
	Stats50 stats50;
	Race race;
	Weapon mh;
	Weapon oh;
	GearBuffs gearbuffs;
	Talents talents;
	Glyphs glyphs;
	
	Stats stats1;
	
	// EP Values Bunker
	private HashMap<String,Double> statsEP = new HashMap<String,Double>();
	private HashMap<String,Double> talentsEP = new HashMap<String,Double>();
	private HashMap<String,Double> glyphsEP = new HashMap<String,Double>();
	private HashMap<String,Double> gearbuffEP = new HashMap<String,Double>();
	private HashMap<Integer,Double> gemEP = new HashMap<Integer,Double>();
	
	JSONObject json = null;
	private IndzCraftLoader loader;
		
	public void calcEP(String ep){
		Stats stats2 = stats1.clone();
		stats2.ep = ep;
		Calc calc = null;
		if(talents.isSubtlety())
			calc = new CalculatorSubtlety(stats2, mh, oh, glyphs, race, gearbuffs);
		else if(talents.isCombat())
			calc = new Calculator(stats2, mh, oh, glyphs, race, gearbuffs);
		else if(talents.isAssa()){
			try {
				throw new Exception("Assasination is not implemented!");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		statsEP.put(ep, Math.abs(calculator.dps1 - calc.dps1)/ap);
		System.out.println("EP " + ep + ": " + Math.abs(calculator.dps1 - calc.dps1)/ap);
	}
	
	public void calcBuffEP(String ep){
		//System.out.println("+--------+");
		Stats stats2 = stats1.clone();
		//System.out.println("gearbuffs:");
		//System.out.println("pp " + gearbuffs.getGearBuffs()[0]);
		GearBuffs gb = new GearBuffs(gearbuffs.getGearBuffs());
		//System.out.println("gb:");
		//gb.showBuffs();
		gb.toggleBuff(ep);
		Calc calc = null;
		if(talents.isSubtlety())
			calc = new CalculatorSubtlety(stats2, mh, oh, glyphs, race, gb);
		else if(talents.isCombat())
			calc = new Calculator(stats2, mh, oh, glyphs, race, gb);
		gearbuffEP.put(ep, Math.abs(calculator.dps1 - calc.dps1)/ap);
		System.out.println("EP Buff " + ep + ": " + Math.abs(calculator.dps1 - calc.dps1)/ap + " DPS: " + Math.abs(calculator.dps1 - calc.dps1));
		System.out.println("EP Buff " + ep + ": " + calculator.dps1 + " " + calc.dps1);
	}
	
	public void calcTalentEP(String ep){
		Stats stats2 = stats1.clone();
		//stats2.talents = talents.clone();
		stats2.talents.ep = ep;
		Calc calc = null;
		if(talents.isSubtlety())
			calc = new CalculatorSubtlety(stats2, mh, oh, glyphs, race, gearbuffs);
		else if(talents.isCombat())
			calc = new Calculator(stats2, mh, oh, glyphs, race, gearbuffs);
		talentsEP.put(ep, Math.abs(calculator.dps1 - calc.dps1)/ap);
		//System.out.println("EP " + ep + ": " + Math.abs(calculator.dps1 - calc.dps1)/ap);
	}
	
	public void calcGlyphEP(String ep){
		Stats stats2 = stats1.clone();
		Glyphs glyphs1 = glyphs.clone();
		//stats2.talents = talents.clone();
		glyphs1.ep_glyph(ep);
		Calc calc = null;
		if(talents.isSubtlety())
			calc = new CalculatorSubtlety(stats2, mh, oh, glyphs1, race, gearbuffs);
		else if(talents.isCombat())
			calc = new Calculator(stats2, mh, oh, glyphs1, race, gearbuffs);
		glyphsEP.put(ep, Math.abs(calculator.dps1 - calc.dps1)/ap);
		//System.out.println("EP " + ep + ": " + Math.abs(calculator.dps1 - calc.dps1)/ap);
	}
	
	public void calcMHDpsEP(){
		Stats stats2 = stats1.clone();
		Weapon mh1 = mh.clone();
		mh1.dps += 1;
		Calc calc = null;
		if(talents.isSubtlety())
			calc = new CalculatorSubtlety(stats2, mh1, oh, glyphs, race, gearbuffs);
		else if(talents.isCombat())
			calc = new Calculator(stats2, mh1, oh, glyphs, race, gearbuffs);
		statsEP.put("mh_dps", Math.abs(calculator.dps1 - calc.dps1)/ap);
		System.out.println("EP mh_dps : " + Math.abs(calculator.dps1 - calc.dps1)/ap);
	}
	
	public void calcOHDpsEP(){
		Stats stats2 = stats1.clone();
		Weapon oh1 = oh.clone();
		oh1.dps += 1;
		Calc calc = null;
		if(talents.isSubtlety())
			calc = new CalculatorSubtlety(stats2, mh, oh1, glyphs, race, gearbuffs);
		else if(talents.isCombat())
			calc = new Calculator(stats2, mh, oh1, glyphs, race, gearbuffs);
		statsEP.put("oh_dps", Math.abs(calculator.dps1 - calc.dps1)/ap);
		System.out.println("EP oh_dps : " + Math.abs(calculator.dps1 - calc.dps1)/ap);
	}
	
	public void calcMHSpeedEP(double ep){
		Stats stats2 = stats1.clone();
		Weapon mh1 = mh.clone();
		mh1.speed = ep;
		Calc calc = null;
		if(talents.isSubtlety())
			calc = new CalculatorSubtlety(stats2, mh1, oh, glyphs, race, gearbuffs);
		else if(talents.isCombat())
			calc = new Calculator(stats2, mh1, oh, glyphs, race, gearbuffs);
		statsEP.put("mh_speed_"+ep, Math.abs(calculator.dps1 - calc.dps1)/ap);
		System.out.println("EP mh_speed_"+ep+" : " + Math.abs(calculator.dps1 - calc.dps1)/ap);
	}
	
	public void calcOHSpeedEP(double ep){
		Stats stats2 = stats1.clone();
		Weapon oh1 = oh.clone();
		oh1.speed = ep;
		Calc calc = null;
		if(talents.isSubtlety())
			calc = new CalculatorSubtlety(stats2, mh, oh1, glyphs, race, gearbuffs);
		else if(talents.isCombat())
			calc = new Calculator(stats2, mh, oh1, glyphs, race, gearbuffs);
		statsEP.put("oh_speed_"+ep, -(calculator.dps1 - calc.dps1)/ap);
		System.out.println("EP oh_speed_"+ep+" : " + -(calculator.dps1 - calc.dps1)/ap);
	}
	
	public IndzCraftCalc(IndzCraftLoader loader, BaseStats base){
		this.loader = loader;
		race = new Race(base.getRace());
		mh = base.getMH();
		oh = base.getOH();
		
		gearbuffs = new GearBuffs();
		if(base.getNumberOfSetItems("T11") >= 2)
			gearbuffs.setBuff("t11_2pc");
		if(base.getNumberOfSetItems("T11") >= 4)
			gearbuffs.setBuff("t11_4pc");
		if(base.getNumberOfSetItems("T12") >= 2)
			gearbuffs.setBuff("t12_2pc");
		if(base.getNumberOfSetItems("T12") >= 4)
			gearbuffs.setBuff("t12_4pc");
		if(base.getNumberOfSetItems("T13") >= 2)
			gearbuffs.setBuff("t13_2pc");
		if(base.getNumberOfSetItems("T13") >= 4)
			gearbuffs.setBuff("t13_4pc");
		if(base.getNumberOfSetItems("Dagger_Stage_1") >= 2)
			gearbuffs.setBuff("dagger_stage1");
		if(base.getNumberOfSetItems("Dagger_Stage_2") >= 2)
			gearbuffs.setBuff("dagger_stage2");
		if(base.getNumberOfSetItems("Dagger_Stage_3") >= 2)
			gearbuffs.setBuff("dagger_stage3");
		gearbuffs.setBuff("leather_specialization");
		
		for (String buff : base.getGearBuffs()) {
			gearbuffs.setBuff(buff);
		}
		gearbuffs.showBuffs();
		
		//System.out.println(oh.dps);
		//System.out.println(base.getTalents()[1]);
		
		//talents = new Talents("0322","2232030310032012321","003");
		talents = new Talents(base.getTalents()[0],base.getTalents()[1],base.getTalents()[2]);
		//glyphs = new Glyphs(new String[]{"sinister_strike","adrenaline_rush","eviscerate","tricks_of_the_trade"});
		String[] g = new String[6];
		base.getGlyphs().toArray(g);
		glyphs = new Glyphs(g);
		
		System.out.println("isSub?: " + talents.isSubtlety());
		System.out.println(base.getStr() + " " +  loader.getBase().getStr());
		System.out.println(base.getAgi() + " " +  loader.getBase().getAgi());
		System.out.println("has: " + base.getHaste() +  " " + loader.getBase().getHaste());
		System.out.println("mas: " + base.getMastery() + " " + loader.getBase().getMastery());
		System.out.println(base.getCrit() + " " + loader.getBase().getCrit());
		System.out.println(base.getHit() + " " + loader.getBase().getHit());
		System.out.println(base.getAp() + " " + loader.getBase().getAp());
		System.out.println(base.getExp() + " " + loader.getBase().getExp());	
		stats = new Stats(base.getStr(),base.getAgi(),base.getAp(),base.getCrit(),base.getHit(),base.getHaste(),base.getExp(),base.getMastery(),talents);
		stats1 = stats.clone();
		// constants...
		
		// subtlety spec
		if(talents.isSubtlety()){
			System.out.println("Subtlety");
			calculator = new CalculatorSubtlety(stats, mh, oh, glyphs, race, gearbuffs);
			System.out.println("DPS: " + calculator.dps1);
			calculator.breakdown();
			
			Stats test_stats1 = stats1.clone();
			test_stats1.ap += 1;
			Calc calculator1 = new CalculatorSubtlety(test_stats1, mh, oh, glyphs, race, gearbuffs);
			ap = Math.abs(calculator.dps1 - calculator1.dps1);
			System.out.println("ap: " + ap/ap);
			statsEP.put("ap", ap/ap);
			
			Stats test_stats2 = stats1.clone();
			test_stats2.agi += 1;
			Calc calculator2 = new CalculatorSubtlety(test_stats2, mh, oh, glyphs, race, gearbuffs);
			System.out.println("agi: " + Math.abs(calculator.dps1 - calculator2.dps1)/ap);
			statsEP.put("agi", Math.abs(calculator.dps1 - calculator2.dps1)/ap);
			
			Stats test_stats3 = stats1.clone();
			test_stats3.haste += 1;
			Calc calculator3 = new CalculatorSubtlety(test_stats3, mh, oh, glyphs, race, gearbuffs);
			System.out.println("haste: " + Math.abs(calculator.dps1 - calculator3.dps1)/ap);
			statsEP.put("haste", Math.abs(calculator.dps1 - calculator3.dps1)/ap);
			
			Stats test_stats4 = stats1.clone();
			test_stats4.crit += 1;
			Calc calculator4 = new CalculatorSubtlety(test_stats4, mh, oh, glyphs, race, gearbuffs);
			System.out.println("crit: " + Math.abs(calculator.dps1 - calculator4.dps1)/ap);
			statsEP.put("crit", Math.abs(calculator.dps1 - calculator4.dps1)/ap);
			
			Stats test_stats5 = stats1.clone();
			test_stats5.mastery += 1;
			Calc calculator5 = new CalculatorSubtlety(test_stats5, mh, oh, glyphs, race, gearbuffs);
			System.out.println("mastery: " + Math.abs(calculator.dps1 - calculator5.dps1)/ap);
			statsEP.put("mastery", Math.abs(calculator.dps1 - calculator5.dps1)/ap);
			
			Stats test_stats_str = stats1.clone();
			test_stats_str.str += 1;
			Calc calculator_str = new CalculatorSubtlety(test_stats_str, mh, oh, glyphs, race, gearbuffs);
			System.out.println("str: " + Math.abs(calculator.dps1 - calculator_str.dps1)/ap);
			statsEP.put("str", Math.abs(calculator.dps1 - calculator_str.dps1)/ap);
		}
		else if(talents.isCombat()){
			System.out.println("Combat");
			calculator = new Calculator(stats, mh, oh, glyphs, race, gearbuffs);
			System.out.println("DPS: " + calculator.dps1);
			calculator.breakdown();
			
			Stats test_stats1 = stats1.clone();
			test_stats1.ap += 1;
			Calculator calculator1 = new Calculator(test_stats1, mh, oh, glyphs, race, gearbuffs);
			ap = Math.abs(calculator.dps1 - calculator1.dps1);
			System.out.println("ap: " + ap/ap);
			statsEP.put("ap", ap/ap);
			
			Stats test_stats2 = stats1.clone();
			test_stats2.agi += 1;
			Calculator calculator2 = new Calculator(test_stats2, mh, oh, glyphs, race, gearbuffs);
			System.out.println("agi: " + Math.abs(calculator.dps1 - calculator2.dps1)/ap);
			statsEP.put("agi", Math.abs(calculator.dps1 - calculator2.dps1)/ap);
			
			Stats test_stats3 = stats1.clone();
			test_stats3.haste += 1;
			Calculator calculator3 = new Calculator(test_stats3, mh, oh, glyphs, race, gearbuffs);
			System.out.println("haste: " + Math.abs(calculator.dps1 - calculator3.dps1)/ap);
			statsEP.put("haste", Math.abs(calculator.dps1 - calculator3.dps1)/ap);
			
			Stats test_stats4 = stats1.clone();
			test_stats4.crit += 1;
			Calculator calculator4 = new Calculator(test_stats4, mh, oh, glyphs, race, gearbuffs);
			System.out.println("crit: " + Math.abs(calculator.dps1 - calculator4.dps1)/ap);
			statsEP.put("crit", Math.abs(calculator.dps1 - calculator4.dps1)/ap);
			
			Stats test_stats5 = stats1.clone();
			test_stats5.mastery += 1;
			Calculator calculator5 = new Calculator(test_stats5, mh, oh, glyphs, race, gearbuffs);
			System.out.println("mastery: " + Math.abs(calculator.dps1 - calculator5.dps1)/ap);
			statsEP.put("mastery", Math.abs(calculator.dps1 - calculator5.dps1)/ap);
			
			Stats test_stats_str = stats1.clone();
			test_stats_str.str += 1;
			Calculator calculator_str = new Calculator(test_stats_str, mh, oh, glyphs, race, gearbuffs);
			System.out.println("str: " + Math.abs(calculator.dps1 - calculator_str.dps1)/ap);
			statsEP.put("str", Math.abs(calculator.dps1 - calculator_str.dps1)/ap);
		}
		
		calcEP("spell_hit");
		calcEP("white_hit");
		calcEP("style_hit");
		calcEP("exp");
		calcEP("exp_mh");
		calcEP("exp_oh");
		
		calcMHDpsEP();
		calcOHDpsEP();
		calcMHSpeedEP(1.8);
		calcMHSpeedEP(2.2);
		calcMHSpeedEP(2.3);
		calcMHSpeedEP(2.4);
		calcMHSpeedEP(2.5);
		calcMHSpeedEP(2.6);
		calcMHSpeedEP(2.7);
		calcMHSpeedEP(2.8);
		calcOHSpeedEP(1.3);
		calcOHSpeedEP(1.4);
		calcOHSpeedEP(1.5);
		calcOHSpeedEP(1.6);
		calcOHSpeedEP(1.7);
		calcOHSpeedEP(1.8);
		calcOHSpeedEP(2.6);
		
		for(String name : talents.getCombat().keySet()){
			calcTalentEP(name);
		}
		for(String name : talents.getAssa().keySet()){
			calcTalentEP(name);
		}
		for(String name : talents.getSubtlety().keySet()){
			calcTalentEP(name);
		}
		
		GearBuffDB gearBuffDB = new GearBuffDB();
		for(Integer id : gearBuffDB.getAll().keySet()){
			calcBuffEP(gearBuffDB.getGearBuff(id).getName());
		}
		calcBuffEP("t11_2pc");
		calcBuffEP("t11_4pc");
		calcBuffEP("t12_2pc");
		calcBuffEP("t12_4pc");
		calcBuffEP("t13_2pc");
		calcBuffEP("t13_4pc");
		calcBuffEP("dagger_stage1");
		calcBuffEP("dagger_stage2");
		calcBuffEP("dagger_stage3");
//		
		calcGlyphEP("sinister_strike");
		calcGlyphEP("adrenaline_rush");
		calcGlyphEP("killing_spree");
		calcGlyphEP("slice_and_dice");
		calcGlyphEP("eviscerate");
		calcGlyphEP("backstab");
		calcGlyphEP("hemorrhage");
		calcGlyphEP("tricks_of_the_trade");
		calcGlyphEP("shadow_dance");
		
		// gem db
		/*System.out.println(statsEP.get("agi"));
		GemDB gdb = new GemDB();
		for(Integer id : gdb.getDB().keySet() ){
			Gem g = gdb.getGem(id);
			double ep = statsEP.get("agi")*g.getAgi();
			ep += statsEP.get("haste")*g.getHaste();
			ep += statsEP.get("white_hit")*g.getHit();
			ep += statsEP.get("mastery")*g.getMastery();
			
			gemEP.put(id, ep);
		}*/
		
		
		json = new JSONObject();
		try {
			json.put("dps", calculator.dps1);
			json.put("stats", statsEP);
			json.put("talents", talentsEP);
			json.put("glyphs", glyphsEP);
			json.put("gearbuff", gearbuffEP);
			json.put("gems", gemEP);
			//System.out.println(json.toString(1));
		} catch (JSONException e) {
			e.printStackTrace();
		}
		
		// items
		/*try {
			double ep = 0;
			IndzCraftLoader icl = new IndzCraftLoader();
			JSONObject data = icl.getItemData2(77188);
			if(data.getJSONArray("itemSpells").length() > 0){
				GearBuffDB.GearBuff gearbuff = gearBuffDB.getGearBuff(77188);
				if(gearbuff != null)
					ep += gearbuffEP.get(gearbuff.getName());
			}
			System.out.println(data.toString(1));
		} catch (JSONException e) {
			e.printStackTrace();
		}*/
	}
	
	public String getJSON(){
		return json.toString();
	}
	
	public double getDPS(){
		return calculator.dps1;
	}
	
	public void calcEP50(String ep){
		Stats50 stats2 = (Stats50) stats1.clone();
		stats2.ep = ep;
		Calc calc = null;
		calc = new CalculatorCombat50(stats2, mh, oh, glyphs, race, gearbuffs);
		statsEP.put(ep, Math.abs(calculator.dps1 - calc.dps1)/ap);
		System.out.println("EP " + ep + ": " + Math.abs(calculator.dps1 - calc.dps1)/ap);
	}
	
	public IndzCraftCalc()
	{
		race = new Race("dwarf");
		
		mh = new Weapon( 1.8, 1572.6, "dagger", "landslide");
		oh = new Weapon( 1.4, 1572.6, "dagger", "landslide");
		
		gearbuffs = new GearBuffs(new String[]{"t12_2pc","t13_2pc","dagger_combat_buff","vial_of_shadows","leather_specialization","wrath_of_unchaining","dagger_stage3"});
		
		talents = new Talents50("322212");
		glyphs = new Glyphs(new String[]{});
		/*	str: 147 147
			agi: 6982 6982
			has: 2881 2881
			mas: 1219 1219
			cri: 745 745
			hit: 1127 1127
			ap:  190 190
			exp: 781 781
		*/
		stats50 = new Stats50(147, 6982, 190, 745, 1127, 2881, 781, 1219,talents);
		stats1 = stats50.clone();
		
		calculator = new CalculatorCombat50(stats50, mh, oh, glyphs, race, gearbuffs);
		System.out.println("DPS: " + calculator.dps1);
		calculator.breakdown();
		
		Stats50 test_stats1 = stats50.clone();
		test_stats1.ap += 1;
		Calc calculator1 = new CalculatorCombat50(test_stats1, mh, oh, glyphs, race, gearbuffs);
		ap = Math.abs(calculator.dps1 - calculator1.dps1);
		System.out.println("ap: " + ap/ap);
		
		Stats50 test_stats2 = stats50.clone();
		test_stats2.agi += 1;
		Calc calculator2 = new CalculatorCombat50(test_stats2, mh, oh, glyphs, race, gearbuffs);
		System.out.println("agi: " + Math.abs(calculator.dps1 - calculator2.dps1)/ap);
		
		Stats50 test_stats3 = stats50.clone();
		test_stats3.haste += 1;
		Calc calculator3 = new CalculatorCombat50(test_stats3, mh, oh, glyphs, race, gearbuffs);
		System.out.println("haste: " + Math.abs(calculator.dps1 - calculator3.dps1)/ap);
		
		Stats50 test_stats4 = stats50.clone();
		test_stats4.crit += 1;
		Calc calculator4 = new CalculatorCombat50(test_stats4, mh, oh, glyphs, race, gearbuffs);
		System.out.println("crit: " + Math.abs(calculator.dps1 - calculator4.dps1)/ap);
		
		Stats50 test_stats5 = stats50.clone();
		test_stats5.mastery += 1;
		Calc calculator5 = new CalculatorCombat50(test_stats5, mh, oh, glyphs, race, gearbuffs);
		System.out.println("mastery: " + Math.abs(calculator.dps1 - calculator5.dps1)/ap);
		
		Stats50 test_stats_str = stats50.clone();
		test_stats_str.str += 1;
		Calc calculator_str = new CalculatorCombat50(test_stats_str, mh, oh, glyphs, race, gearbuffs);
		System.out.println("str: " + Math.abs(calculator.dps1 - calculator_str.dps1)/ap);
		
			
		for (String ep : new String[]{"spell_hit","white_hit","style_hit","exp","exp_mh","exp_oh"}) {
			calcEP50(ep);
		}
		
//			
//		calcEP("t11_2pc");
//		calcEP("t11_4pc");
//		
//		calcEP("left_eye_of_rajh");
//		calcEP("key_to_the_endless_chamber");
//		calcEP("prestors_talisman_of_machination");
//		calcEP("trinket_hurricane");
//		
//		calcEP("matrix_restabilisator");
//		calcEP("the_hungerer");
	
	}
	
	public double calcItemEP(ItemEquiped item){
		if(calculator == null)
			return 0.0;
		double ep = 0.;
		ep += statsEP.get("agi")*item.getAgi();
		ep += statsEP.get("white_hit")*item.getHit();
		ep += statsEP.get("exp")*item.getExp();
		ep += statsEP.get("haste")*item.getHaste();
		ep += statsEP.get("mastery")*item.getMastery();
		ep += statsEP.get("crit")*item.getCrit();
		
		if(item.dps > 0 && item.getSpeed() >= 1.8)
		{
			//System.out.println("Item ep before dps:" + ep);
			ep += statsEP.get("mh_dps")*item.dps;
			//ep += statsEP.get("mh_speed_"+item.getSpeed());
			//System.out.println("Item ep after dps:" + ep);
		}else if(item.dps > 0 && item.getSpeed() <= 1.8){
			//System.out.println("Item ep before dps:" + ep);
			ep += statsEP.get("oh_dps")*item.dps;
			ep += statsEP.get("oh_speed_"+item.getSpeed());
			//System.out.println("Item ep after dps:" + ep);
		}
		
		// gems
		double gemMatchEP = 0.;
		String[] gemSlot = item.getGemSlot();
		for(int i = 0;i< gemSlot.length;i++){
			if(gemSlot[i].equals("RED") || gemSlot[i].equals("PRISMATIC")){
				//if(item.getGem(i) != null)
				//	ep += calcGemEP(item.getGem(i));
				gemMatchEP += calcGemEP(loader.getGemDB().getGem(71879)); // TODO fixed best gems, calculate them out is for sure better
			}else if(gemSlot[i].equals("YELLOW")){
				//if(item.getGem(i) != null)
				//	ep += calcGemEP(item.getGem(i));
				gemMatchEP += calcGemEP(loader.getGemDB().getGem(71848));
			}else if(gemSlot[i].equals("BLUE")){
				//if(item.getGem(i) != null)
				//	ep += calcGemEP(item.getGem(i));
				gemMatchEP += calcGemEP(loader.getGemDB().getGem(71862));
			}
		}
		
		//System.out.println("gem Match EP: " + gemMatchEP);
		
		double gemOnlyBestEP = 0.;
		boolean gemOnlyBestMatch = true;
		for(int i = 0;i< gemSlot.length;i++){
			if(!gemSlot[i].equals("")){
				gemOnlyBestEP += calcGemEP(loader.getGemDB().getGem(71879));
				if(!gemSlot[i].equals("RED") || !gemSlot[i].equals("PRISMATIC")){
					gemOnlyBestMatch = false;
				}
			}
		}
		
		//System.out.println(gemOnlyBestEP);
		
		double gemSocketEP = 0.;
		if(item.getSocketBonus() != null){
			SocketBonus sb = item.getSocketBonus();
			gemSocketEP += statsEP.get("agi")*sb.getAgi();
			gemSocketEP += statsEP.get("white_hit")*sb.getHit();
			gemSocketEP += statsEP.get("exp")*sb.getExp();
			gemSocketEP += statsEP.get("haste")*sb.getHaste();
			gemSocketEP += statsEP.get("mastery")*sb.getMastery();
			gemSocketEP += statsEP.get("crit")*sb.getCrit();
		}
		//System.out.println("gem socket ep:" + item.getName() + " " + gemSocketEP);
		gemMatchEP += gemSocketEP;
		if(gemOnlyBestMatch)
			gemOnlyBestEP += gemSocketEP;
		//System.out.println("gemMatchEP" + item.getName() + " " + gemMatchEP);
		//System.out.println("gemOnlyBestEP" + item.getName() + " " + gemOnlyBestEP);
		ep += Math.max(gemMatchEP, gemOnlyBestEP);
		
		
		// TODO get Best Reforge option (e.g. crit->exp)
		Entry<String, Double> min = null;
		Entry<String, Double> max = null;
		for (Entry<String, Double> entry : statsEP.entrySet()) {
		    if(Arrays.asList(new String[]{"exp","white_hit","crit","haste","mastery"}).contains(entry.getKey())) {
		    	if(hasItemStat(item,entry.getKey()) && (min == null || min.getValue() > entry.getValue())) {
			        min = entry;
			    }
			    if(!hasItemStat(item,entry.getKey()) && (max == null || max.getValue() < entry.getValue())) {
			    	max = entry;
			    }
		    }
		}
//		System.out.println(min.getKey() + " " + min.getValue());
//		System.out.println(max.getKey() + " " + max.getValue());
		if(min != null && max != null){
			int value = 0;
			if(min.getKey().equals("crit")){
				value = (int)Math.floor(item.getCrit()*0.4);
			}else if(min.getKey().equals("haste")){
				value = (int)Math.floor(item.getHaste()*0.4);
			}else if(min.getKey().equals("white_hit")){
				value = (int)Math.floor(item.getHit()*0.4);
			}else if(min.getKey().equals("mastery")){
				value = (int)Math.floor(item.getMastery()*0.4);
			}else if(min.getKey().equals("exp")){
				value = (int)Math.floor(item.getExp()*0.4);
			}
			double lowEP = min.getValue()*value;
			double highEP = max.getValue()*value;
			
			//System.out.println(item.getName() + " " + value + " " + lowEP + " " + highEP);
			
			ep += highEP - lowEP;
		}
		
		// gearbuffs...
		if(item.getGearBuff() != null){
			ep += gearbuffEP.get(item.getGearBuff());
		}
		return ep;
	}
	
	public boolean hasItemStat(ItemEquiped item, String matchingEP){
		if(matchingEP.equals("white_hit") && item.getHit() > 0){
			return true;
		}else if(matchingEP.equals("crit") && item.getCrit() > 0){
			return true;
		}else if(matchingEP.equals("haste") && item.getHaste() > 0){
			return true;
		}else if(matchingEP.equals("mastery") && item.getMastery() > 0){
			return true;
		}else if(matchingEP.equals("exp") && item.getExp() > 0){
			return true;
		}
		return false;
	}

	public double calcGemEP(Gem gem) {
		double ep = statsEP.get("agi")*gem.getAgi();
		ep += statsEP.get("white_hit")*gem.getHit();
		//ep += statsEP.get("exp")*gem.getExp();
		ep += statsEP.get("haste")*gem.getHaste();
		ep += statsEP.get("mastery")*gem.getMastery();
		//ep += statsEP.get("crit")*gem.getCrit();
		return ep;
	}
	
	public double calcEnchantEP(Enchant e) {
		if(e == null)
			return 0;
		double ep = statsEP.get("agi")*e.getAgi();
		ep += statsEP.get("white_hit")*e.getHit();
		ep += statsEP.get("exp")*e.getExp();
		ep += statsEP.get("haste")*e.getHaste();
		ep += statsEP.get("mastery")*e.getMastery();
		ep += statsEP.get("crit")*e.getCrit();
		return ep;
	}
	
	public double calcReforgeEP(ItemEquiped i,Reforge r){
		if(i == null || r == null)
			return 0;
		
		int value = 0;
		double ep = 0;
		if(r.getFrom().equals("Haste Rating")){
			value = (int) Math.floor(i.getHaste() * 0.4);
			ep -= value * statsEP.get("haste");
		}else if(r.getFrom().equals("Hit Rating")){
			value = (int) Math.floor(i.getHit() * 0.4);
			ep -= value * statsEP.get("white_hit");
		}else if(r.getFrom().equals("Crit Rating")){
			value = (int) Math.floor(i.getCrit() * 0.4);
			ep -= value * statsEP.get("crit");
		}else if(r.getFrom().equals("Mastery Rating")){
			value = (int) Math.floor(i.getMastery() * 0.4);
			ep -= value * statsEP.get("mastery");
		}else if(r.getFrom().equals("Expertise Rating")){
			value = (int) Math.floor(i.getExp() * 0.4); 
			ep -= value * statsEP.get("exp");
		}
		
		if(r.getTo().equals("Haste Rating")){
			ep += value * statsEP.get("haste");
		}else if(r.getTo().equals("Hit Rating")){
			ep += value * statsEP.get("white_hit");
		}else if(r.getTo().equals("Crit Rating")){
			ep += value * statsEP.get("crit");
		}else if(r.getTo().equals("Mastery Rating")){
			ep += value * statsEP.get("mastery");
		}else if(r.getTo().equals("Expertise Rating")){
			ep += value * statsEP.get("exp");
		}
		
		return ep;
	}
	
	public HashMap<String, Double> getStatsEP(){
		return statsEP;
	}
	
	

}
